第 8 章:遠程分支使用與管理
遠程引用是對遠程倉庫的引用(指針),包括分支、標簽等等。 你可以通過 git ls-remote $REMOTE
來顯式地獲得遠程引用的完整列表, 或者通過 git remote show $REMOTE
獲得遠程分支的更多 信息。 然而,一個更常見的做法是利用遠程跟蹤分支。
遠程跟蹤分支是遠程分支狀態的引用。它們是你無法移動的本地引用。一旦你進行了網絡通信, Git 就會為你移動它們以精確反映遠程倉庫的狀態。請將它們看做書簽, 這樣可以提醒你該分支在遠程倉庫中的位置就是你最後一次連接到它們的位置。
它們以 <remote>/<branch>
的形式命名。 例如,如果你想要看你最後一次與遠程倉庫 origin 通信時 master 分支的狀態,你可以查看 origin/master 分支。 你與同事合作解決一個問題並且他們推送了一個 iss53 分支,你可能有自己的本地 iss53 分支, 然而在服務器上的分支會以 origin/iss53 來表示。
這可能有一點兒難以理解,讓我們來看一個例子。 假設你的網絡里有一個在 git.ourcompany.com 的 Git 服務器。 如果你從這里克隆,Git 的 clone 命令會為你自動將其命名為 origin,拉取它的所有數據, 創建一個指向它的 master 分支的指針,並且在本地將其命名為 origin/master。 Git 也會給你一個與 origin 的 master 分支在指向同一個地方的本地 master 分支,這樣你就有工作的基礎。
遠程倉庫名字 “origin” 與分支名字 “master” 一樣,在 Git 中並沒有任何特別的含義一樣。 同時 “master” 是當你運行 git init
時默認的起始分支名字,原因僅僅是它的廣泛使用, “origin” 是當你運行 git clone 時默認的遠程倉庫名字。 如果你運行 git clone -o booyah
,那麽你默認的遠程分支名字將會是 booyah/master。
如果你在本地的 master 分支做了一些工作,在同一段時間內有其他人推送提交到 git.ourcompany.com 並且更新了它的 master 分支,這就是說你們的提交歷史已走向不同的方向。 即便這樣,只要你保持不與 origin 服務器連接(並拉取數據),你的 origin/master 指針就不會移動。
如果要與給定的遠程倉庫同步數據,運行 git fetch <remote>
命令(在本例中為 git fetch origin)。 這個命令查找 origin
是哪一個服務器(在本例中,它是 git.ourcompany.com, 從中抓取本地沒有的數據,並且更新本地數據庫,移動 origin/master 指針到更新之後的位置。
為了演示有多個遠程倉庫與遠程分支的情況, 我們假定你有另一個內部 Git 服務器,僅服務於你的某個敏捷開發團隊。 這個服務器位於 git.team1.ourcompany.com。 你可以運行 git remote add
命令添加一個新的遠程倉庫引用到當前的項目,這個命令我們會在 Git 基礎 中詳細說明。 將這個遠程倉庫命名為 teamone,將其作為完整 URL 的縮寫。
現在,可以運行 git fetch teamone 來抓取遠程倉庫 teamone 有而本地沒有的數據。 因為那台服務器上現有的數據是 origin 服務器上的一個子集, 所以 Git 並不會抓取數據而是會設置遠程跟蹤分支 teamone/master 指向 teamone 的 master 分支。
推送分支
當你想要公開分享一個分支時,需要將其推送到有寫入權限的遠程倉庫上。 本地的分支並不會自動與遠程倉庫同步——你必須顯式地推送想要分享的分支。 這樣,你就可以把不願意分享的內容放到私人分支上,而將需要和別人協作的內容推送到公開分支。
如果希望和別人一起在名為 serverfix 的分支上工作,你可以像推送第一個分支那樣推送它。 運行 git push <remote> <branch>
git push origin serverfix
Counting objects: 24, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (15/15), done.
Writing objects: 100% (24/24), 1.91 KiB | 0 bytes/s, done.
Total 24 (delta 2), reused 0 (delta 0)
To https://github.com/schacon/simplegit
- [new branch] serverfix -> serverfix
這里有些工作被簡化了。 Git 自動將 serverfix 分支名字展開為 refs/heads/serverfix:refs/heads/serverfix, 那意味著,“推送本地的 serverfix 分支來更新遠程倉庫上的 serverfix 分支。” 我們將會詳細學習 Git 內部原理 的 refs/heads/ 部分, 但是現在可以先把它放在兒。你也可以運行
git push origin serverfix:serverfix
, 它會做同樣的事——也就是說“推送本地的 serverfix 分支,將其作為遠程倉庫的 serverfix 分支” 可以通過這種格式來推送本地分支到一個命名不相同的遠程分支。 如果並不想讓遠程倉庫上的分支叫做 serverfix,可以運行git push origin serverfix:awesomebranch
來將本地的 serverfix 分支推送到遠程倉庫上的 awesomebranch 分支。
如果你正在使用 HTTPS URL 來推送,Git 服務器會詢問用戶名與密碼。 默認情況下它會在終端中提示服務器是否允許你進行推送。
如果不想在每一次推送時都輸入用戶名與密碼,你可以設置一個 “credential cache”。 最簡單的方式就是將其保存在內存中幾分鐘,可以簡單地運行 git config --global credential.helper cache
來設置它。
想要了解更多關於不同驗證緩存的可用選項,查看 憑證存儲。
下一次其他協作者從服務器上抓取數據時,他們會在本地生成一個遠程分支 origin/serverfix,指向服務器的 serverfix 分支的引用:
git fetch origin
remote: Counting objects: 7, done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 0), reused 3 (delta 0)
Unpacking objects: 100% (3/3), done.
From https://github.com/schacon/simplegit
- [new branch] serverfix → origin/serverfix 要特別注意的一點是當抓取到新的遠程跟蹤分支時,本地不會自動生成一份可編輯的副本(拷貝)。 換一句話說,這種情況下,不會有一個新的 serverfix 分支——只有一個不可以修改的 origin/serverfix 指針。
可以運行 git merge origin/serverfix 將這些工作合並到當前所在的分支。 如果想要在自己的 serverfix 分支上工作,可以將其建立在遠程跟蹤分支之上:
git checkout -b serverfix origin/serverfix
Branch serverfix set up to track remote branch serverfix from origin.
Switched to a new branch 'serverfix'
這會給你一個用於工作的本地分支,並且起點位於 origin/serverfix。
跟蹤分支
從一個遠程跟蹤分支檢出一個本地分支會自動創建所謂的“跟蹤分支”(它跟蹤的分支叫做“上遊分支”)。 跟蹤分支是與遠程分支有直接關系的本地分支。 如果 在一個跟蹤分支上輸入 git pull,Git 能自動地識別去哪個服務器上抓取、合並到哪個分支。
當克隆一個倉庫時,它通常會自動地創建一個跟蹤 origin/master 的 master 分支。 然而,如果你願意的話可以設置其他的跟蹤分支,或是一個在其他遠程倉庫上的跟蹤分支,又或者不跟蹤 master 分支。 最簡單的實例就是像之前看到的那樣,運行 git checkout -b <branch> <remote>/<branch>
。 這是一個十分常用的操作所以 Git 提供了 --track 快捷方式:
git checkout --track origin/serverfix
Branch serverfix set up to track remote branch serverfix from origin. Switched to a new branch 'serverfix' 由於這個操作太常用了,該捷徑本身還有一個捷徑。 如果你嘗試檢出的分支 (a) 不存在且 (b) 剛好只有一個名字與之匹配的遠程分支,那麽 Git 就會為你創建一個跟蹤分支:
git checkout serverfix
Branch serverfix set up to track remote branch serverfix from origin. Switched to a new branch 'serverfix' 如果想要將本地分支與遠程分支設置為不同的名字,你可以輕松地使用上一個命令增加一個不同名字的本地分支:
git checkout -b sf origin/serverfix
Branch sf set up to track remote branch serverfix from origin.
Switched to a new branch 'sf'
現在,本地分支 sf 會自動從 origin/serverfix 拉取。
設置已有的本地分支跟蹤一個剛剛拉取下來的遠程分支,或者想要修改正在跟蹤的上遊分支, 你可以在任意時間使用 -u 或 --set-upstream-to 選項運行 git branch 來顯式地設置。
git branch -u origin/serverfix
Branch serverfix set up to track remote branch serverfix from origin.
當設置好跟蹤分支後,可以通過簡寫 @{upstream}
或 @{u}
來引用它的上遊分支。 所以在 master 分支時並且它正在跟蹤 origin/master 時,如果願意的話可以使用 git merge @{u}
來取代 git merge origin/master
。
如果想要查看設置的所有跟蹤分支,可以使用 git branch 的 -vv 選項。 這會將所有的本地分支列出來並且包含更多的信息,如每一個分支正在跟蹤哪個遠程分支與本地分支是否是領先、落後或是都有。
git branch -vv
#iss53 7e424c3 [origin/iss53: ahead 2] forgot the brackets
#master 1ae2a45 [origin/master] deploying index fix
#serverfix f8674d9 [teamone/server-fix-good: ahead 3, behind 1] this should do it
testing 5ea463a trying something new
這里可以看到 iss53 分支正在跟蹤 origin/iss53 並且 “ahead” 是 2,意味著本地有兩個提交還沒有推送到服務器上。 也能看到 master 分支正在跟蹤 origin/master 分支並且是最新的。 接下來可以看到 serverfix 分支正在跟蹤 teamone 服務器上的 server-fix-good 分支並且領先 3 落後 1, 意味著服務器上有一次提交還沒有合並入同時本地有三次提交還沒有推送。 最後看到 testing 分支並沒有跟蹤任何遠程分支。
需要重點注意的一點是這些數字的值來自於你從每個服務器上最後一次抓取的數據。 這個命令並沒有連 接服務器,它只會告訴你關於本地緩存的服務器數據。 如果想要統計最新的領先與落後數字,需要在運行此命令前抓取所有的遠程倉庫。 可以像這樣做:
git fetch --all
git branch -vv
拉取
當 git fetch
命令從服務器上抓取本地沒有的數據時,它並不會修改工作目錄中的內容。 它只會獲取數據然後讓你自己合並。 然而,有一個命令叫作 git pull
在大多數情況下它的含義是一個 git fetch
緊接著一個 git merge
命令。 如果有一個像之前章節中演示的設置好的跟蹤分支,不管它是顯式地設置還是通過 clone 或 checkout 命令為你創建的,git pull
都會查找當前分支所跟蹤的服務器與分支, 從服務器上抓取數據然後嘗試合並入那個遠程分支。
由於 git pull
的魔法經常令人困惑所以通常單獨顯式地使用 fetch 與 merge 命令會更好一些。
刪除遠程分支
假設你已經通過遠程分支做完所有的工作了——也就是說你和你的協作者已經完成了一個特性, 並且將其合並到了遠程倉庫的 master 分支(或任何其他穩定代碼分支)。 可以運行帶有 --delete 選項的 git push 命令來刪除一個遠程分支。 如果想要從服務器上刪除 serverfix 分支,運行下面的命令:
git push origin --delete serverfix
To https://github.com/schacon/simplegit
—delete serverfix
基本上這個命令做的只是從服務器上移除這個指針。 Git 服務器通常會保留數據一段時間直到垃圾回收運行,所以如果不小心刪除掉了,通常是很容易恢覆的。